
use super::common;
use super::common::console;
use super::common::Name;
use super::common::ToF64;


/**
 * width 的变更以 left 为基
 * height 的变更以 bottom 为基
 * 动画位置与 Character 位置无关
 */
#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct AnimationFrameData
{
    width: f64,
    height: f64,
}
impl common::Json for AnimationFrameData {}
impl common::FromInput for AnimationFrameData {
    fn from_input() -> Self {
        println!();
        console::print_and_flush("width: ");
        let width: f64 = console::read().to_f64();
        console::print_and_flush("height: ");
        let height: f64 = console::read().to_f64();
        Self {
            width,
            height
        }
    }
}
impl AnimationFrameData
{
    pub fn get_width(&self) -> f64 { self.width }
    pub fn get_height(&self) -> f64 { self.height }
    pub fn width(&self) -> f64 { self.width }
    pub fn height(&self) -> f64 { self.height }
}
type AnimationFrameList = ::std::vec::Vec<AnimationFrameData>;


#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct AnimationData
{
    name: String,
    fps: f64,
    frames: AnimationFrameList
}

impl common::Json for AnimationData {}
impl common::FromInput for AnimationData {
    fn from_input() -> Self {
        println!();
        console::print_and_flush("animation name: ");
        let name = console::read();
        console::print_and_flush("fps: ");
        let fps = console::read().to_f64();
        console::print_and_flush("frames count: ");
        let mut count: u32 = 0;
        match console::read().parse() {
            Ok(c) => count = c,
            Err(e) => println!("{}", e),
        }

        let mut frames_data: AnimationFrameList = AnimationFrameList::new();
        for _index in 0..count {
            frames_data.push(AnimationFrameData::from_input());
        }

        Self { name, fps, frames: frames_data }
    }
}
impl AnimationData {

    pub fn new(name: String, fps: f64, frames: AnimationFrameList) -> Self
    {
        Self { name, fps, frames }
    }
    pub fn get_fps(&self) -> f64 { self.fps }
    pub fn get_frames(&self) -> &AnimationFrameList { &self.frames }
    pub fn get_frame(&self, index: usize) -> &AnimationFrameData { &self.frames.get(index).as_ref().unwrap() }

}
/* 实现 Name特性 以实现 MultiJson特性 */
impl common::Name for AnimationData
{
    fn name(&self) -> &String { &self.name }
    fn get_name(&self) -> &String { &self.name }
}
type AnimationMap = ::std::collections::HashMap<String, AnimationData>;




#[derive(Debug)]
#[derive(Clone)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
pub struct AnimationManager
{
    animation_map: AnimationMap,
    playing: Option<AnimationData>, // come from animation_map
    frame_index: usize,
}
impl Default for AnimationManager
{
    fn default() -> Self {
        Self {
            animation_map: AnimationMap::new(),
            playing: Option::None,
            frame_index: 0
        }
    }
}
impl common::MultiJson for AnimationManager
{
    /* 如果没加载到文件则返回结果为Option::None */
    fn from_multi_json(dir_path: &str) -> Option<Self> {
        let option = AnimationMap::from_multi_json(dir_path);
        let map = if option.is_none() {
            eprintln!("AnimationManager.from_multi_json option is none");
            eprintln!("没有加载到动画文件");
            return Option::None;//结束该函数
        } else { option.unwrap() };
        Option::Some (
            Self {
                animation_map: map,
                playing: Option::None,
                frame_index: 0
            }
        )
    }

    /* 写出animation数据 */
    fn write_multi_json(&self, dir_path: &str) {
        self.animation_map.write_multi_json(dir_path);
    }
}
impl AnimationManager
{
    pub fn new() -> Self
    {
        Default::default()
    }

    pub fn get_animation_map(&self) -> &AnimationMap { &self.animation_map }
    pub fn get_playing(&self) -> &Option<AnimationData> { &self.playing }
    pub fn get_frame_index(&self) -> usize { self.frame_index }
    pub fn get_current_frame(&self) -> Option<&AnimationFrameData>
    {
        if self.playing.is_none()
        {
            eprintln!("get_current_frame() self.playing is none");
            eprintln!("当前播放动画未设置");
            return Option::None;
        }
        let animation = self.playing.as_ref().unwrap();
        Option::Some(animation.get_frame(self.get_frame_index()))
    }
    pub fn next_frame(&mut self) { self.set_frame_index(self.frame_index + 1); }
    pub fn set_frame_index(&mut self, index: usize)
    {
        if self.playing.is_none()
        {
            self.frame_index = 0;
            return;
        }

        let animation = self.playing.as_ref().unwrap();
        if index >= animation.frames.len()
        {
            self.frame_index = animation.frames.len() - 1;//最后一帧
            return;
        }
        self.frame_index = index;
    }
    pub fn play(&mut self, name: &str)
    {
        let option = self.animation_map.get(name);
        if option.is_none()
        {
            eprintln!("play() self.playing is none");
            eprintln!("动画不存在");
        }
        self.playing = Option::Some(option.unwrap().clone());

    }
    pub fn stop_play(&mut self) { self.playing = Option::None; }


    pub fn get_animation(&self, name: &str) -> Option<&AnimationData> { self.animation_map.get(name) }
    pub fn insert_animation(&mut self, animation: AnimationData) -> &mut Self
    {
        self.animation_map.insert(animation.get_name().to_string(), animation);
        self
    }
    pub fn remove_animation(&mut self, name: &str) -> &mut Self
    {
        self.animation_map.remove(name);
        self
    }
}



pub type AnimationManagerMap = ::std::collections::HashMap<String, AnimationManager>;
impl common::MultiJson for AnimationManagerMap
{
    /* 如果没加载到文件则返回结果为Option::None */
    /* 这个会扫描dir_path所指文件夹里面的文件夹的json文件 */
    fn from_multi_json(dir_path: &str) -> Option<Self>
    {
        let result = ::std::fs::read_dir(dir_path);
        if result.is_err()
        {
            eprintln!("result is err");
            eprintln!("{}", result.err().unwrap());
            eprintln!("文件夹读取失败");
            return Option::None;
        }
        let dir = result.unwrap();
        let mut map = AnimationManagerMap::default();
        for entry in dir
        {
            if entry.is_err()
            {
                eprintln!("{}", entry.err().unwrap());
                continue;//读取下一个条目
            }

            let dir = entry.unwrap();
            let file_type = match dir.file_type() {
                Ok(t) => t,
                Err(e) => {
                    eprintln!("{}", e);
                    eprintln!("file_type error");
                    continue;//读取下一个条目
                }
            };
            if file_type.is_file() {
                continue;//不是文件夹，读取下一个条目
            }

            let path = dir.path();
            let animation_dir_path_str = path.to_str().unwrap();
            let manager = AnimationManager::from_multi_json(animation_dir_path_str);
            if manager.is_none()
            {
                continue;//没加载到文件，读取下一个条目
            }
            let dir_name = dir.file_name().to_str().unwrap().to_string();
            map.insert(dir_name.to_string(), manager.unwrap());
            println!("文件夹{}的动画数据已加载", dir_name);
        }

        if map.is_empty() { return Option::None; }
        Option::Some(map)
    }

    /* 会输出一个目录，里面再有目录 */
    fn write_multi_json(&self, dir_path: &str)
    {
        for (name, manager) in self
        {
            let path = format!("{}/{}", dir_path, name);
            manager.write_multi_json(path.as_str());
        }
    }
}


